#include "StdAfx.h"
#include "P2P.h"

LIBVERSION __p2p_client_libversion = p2p_client_libversion;

static bool CheckVersion(LIBVERSION libversion)
{
    if (__p2p_client_libversion == libversion)
    {
        return true;
    }

    return false;
}
IP2P* CreateP2PClient( IP2PSessionManager* p2p_session_manager, LIBVERSION libversion )
{
    if (!CheckVersion(libversion))
    {
        return NULL;
    }

    CP2P* p2p_client = new CP2P;
    if (p2p_client)
    {
        if (!p2p_client->Init(p2p_session_manager))
        {
            p2p_client->UnInit();
            delete p2p_client;
            p2p_client = NULL;
        }
    }

    return p2p_client;
}

CP2P::CP2P(void):m_p2p_session_manager(this), m_p2p_timer_manager(this), m_host(this), m_host_check(this), m_p2p_protocol_impl(this)
{
}

CP2P::~CP2P(void)
{
}

bool CP2P::Init( IP2PSessionManager* p2p_session_manager )
{
    m_net_manager = CreateNetManager(NET_IO_COMPLETEPORT, &m_p2p_session_manager);
    if (!m_net_manager)
    {
        return false;
    }

    m_timer_manager = CreateTimerManager(&m_p2p_timer_manager);
    if (!m_timer_manager)
    {
        return false;
    }

    set_p2p_session_call_back(p2p_session_manager);
    m_host.set_session(NULL);
    set_p2p_id(0);
    set_nat_type(0);

    return true;
}

void CP2P::UnInit( void )
{

}

bool CP2P::Login( const char* p2p_server_ip, const UINT16 p2p_server_port, const UINT16 p2p_nat_test_port )
{
    if (m_host.get_session())
    {
        return true;
    }

    HSESSION session = m_net_manager->Connect(p2p_server_ip, p2p_server_port, 1024, 1024, &m_pkg_parser, NULL, 0, true);

    if (!session)
    {
        return false;
    }

    m_net_manager->SetSessionUserData(session, &m_host);

    m_host.set_session(session);

    //m_p2p_timer_manager.AddTimer(&m_host_check, false);

    set_nat_test_port(htons(p2p_nat_test_port));

    set_p2p_id(0);
    set_nat_type(0);

    return true;
}

bool CP2P::AddPeer( UINT32 peer_p2p_id )
{
    if (get_p2p_session_manager().FindP2PSession(peer_p2p_id))
    {
        return true;
    }

    ConnectPeerReq stReq;
    stReq.dst_p2p_id = peer_p2p_id;

    return m_host.SendPkg(&stReq);
}

void CP2P::DelPeer( UINT32 peer_p2p_id )
{
    CP2PSession* p2p_session = get_p2p_session_manager().FindP2PSession(peer_p2p_id);
    if (p2p_session)
    {
        p2p_session->DisConnect();
    }
}

bool CP2P::SendPeer( UINT32 peer_p2p_id, const char* pData, const INT32 iLen )
{
    CP2PSession* p2p_session = get_p2p_session_manager().FindP2PSession(peer_p2p_id);

    if (p2p_session && p2p_session->get_session())
    {
        INT32 pkg_len = iLen + sizeof(INT32);
        if (m_net_manager->Send(p2p_session->get_session(), (char*)&pkg_len, sizeof(pkg_len)))
        {
            return m_net_manager->Send(p2p_session->get_session(), pData, iLen);
        }

        return false;
    }

    return false;
}

void CP2P::SetPeerUserData( UINT32 peer_p2p_id, void* user_data )
{

}

void* CP2P::GetPeerUserData( UINT32 peer_p2p_id )
{
    return NULL;
}

bool CP2P::Run( void )
{
    bool busy = false;

    if (m_net_manager->Run(10))
    {
        busy = true;
    }

    if (m_timer_manager->Update())
    {
        busy = true;
    }

    return busy;
}

bool CP2P::Open( UINT32 ip, UINT16 port )
{
    char local_ip[32];

    sockaddr_in addr;
    addr.sin_addr.s_addr = ip;
    strcpy(local_ip, inet_ntoa(addr.sin_addr));

    m_listener = m_net_manager->Listen(local_ip, ntohs(port), 1024, 1024, &m_pkg_parser, true);

    if (m_listener)
    {
        return true;
    }

    return false;
}

